home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / pnuc3 < prev    next >
Text File  |  1999-01-10  |  20KB  |  796 lines

  1. \                    ===========================
  2. \                            APPLEEVENTS
  3. \                    ===========================
  4.  
  5. : AEHANDLER  ( ^AE ^AEReply RefCon -- )
  6.  
  7. \ Put at the start of an AppleEvent handler proc.  Pops the parms into
  8. \ the appropriate locations.
  9.  
  10. ;
  11.  
  12.     
  13. : GOTPARMS?  ( -- rc )
  14.  
  15. \ This can be called at the end of a handler, to check if we got all
  16. \ the parameters.
  17.  
  18. ;
  19.  
  20.  
  21. : ?RTNAEPMISSED  ( rc -- rc' )
  22.  
  23. \ This can be called after calling GotParms? to convert the return code
  24. \ from that word to the appropriate return code to return to the caller
  25. \ of the handler.  If GotParms? returns false, that means we missed
  26. \ a parm, so we return -1715.  If GotParms? returned anything non-zero,
  27. \ that means we got all the parms, so we return zero.
  28.  
  29.     IF  0  ELSE  -1715  THEN  ;
  30.  
  31.  
  32. \                    ========================
  33. \                         ERROR HANDLING
  34. \                    ========================
  35.  
  36. (*    This is unfortunately a bit complicated.  The basic mechanism is
  37.     the standard CATCH and THROW.  Apart from THROW, there are three
  38.     words which signal an error - ABORT, ABORT" and our Mops error
  39.     dump word DIE.
  40.     
  41.     The standard says that if CATCH and THROW are
  42.     implemented, ABORT throws a -1, and ABORT" throws a -2.  This
  43.     allows a throw handler to catch these and override the default
  44.     error action.
  45.     
  46.     If no throw handler is installed, the default action
  47.     occurs.  For this default action, we define DFLT_ABORT and DFLT_ERR
  48.     (I assume I didn't want to call it dflt-abort" since it doesn't take
  49.     an inline string - that was stored by ABORT".)
  50.  
  51.     We follow the same philosophy with DIE.  The error code passed to
  52.     DIE is simply THROWn (note we don't use any negative error code
  53.     for a non-ANSI Mops error), which allows a throw handler to intercept
  54.     it.  And we define DFLT_DIE to be executed if there's no throw handler,
  55.     which does our normal Mops error dump to the Mops window.
  56. *)
  57.  
  58.  
  59. forward QUIT
  60. forward (.stk)
  61. forward .objOrRA
  62. forward tstr
  63.  
  64.  
  65. 0        value    origCDP            \ set to the "normal" CDP if we're
  66.                                 \  temporarily in the execution buffer
  67.  
  68.  
  69. : TypeErrNum  ( err# -- )
  70.     instld?  ?EXIT
  71.     cr ." Error # "  dup .  space  tstr
  72. ;
  73.  
  74.  
  75. (*    SAVE_ERR ( addr len ^ed -- )
  76.     saves all the info needed for an error dump, for later use by the default
  77.     error handling routine which may be called after the stacks have been
  78.     reset.  This way, THROW can be called without our having to know if a
  79.     non-default error routine is installed or not.  ( addr len ) specifies
  80.     an error text string.  We may pass ( err# -1 ), in which case err# is a
  81.     Mops error number, whose text can be typed via TSTR.  For ABORT, which
  82.     has no error string, we pass ( 0 0 ).
  83.  
  84.     Our normal error word is DIE, which calls SAVE_ERR, then calls
  85.     ThrowWithInfo, the alternative to THROW.
  86. *)
  87.  
  88. : svStk  { start finish ^ed \ cnt -- ^ed' }
  89.     finish start -  2 >>  -> cnt        \ ## assumes 4-byte cells
  90.     cnt maxDump min  -> cnt
  91.     
  92.     cnt  ^ed !  1cell ++> ^ed
  93.     cnt FOR  start @  ^ed !  1cell ++> start  1cell ++> ^ed  NEXT
  94.     ^ed
  95. ;
  96.  
  97. : SAVE_ERR  { addr len \ ^ed -- }
  98.     ^errDump -> ^ed
  99.     len        ^ed !    1cell ++> ^ed
  100.     addr    ^ed !    1cell ++> ^ed        \ save the two parms
  101.     (^base)    ^ed !    1cell ++> ^ed        \ save ptr to current obj (-1 if none)
  102.     SP SP0 ^ed svStk  -> ^ed            \ save data stack
  103.     RP 20 +                                \ don't want to display the Rstack
  104.                                         \  cells with our error-handling calls
  105.                                         \  and saved regs
  106.     RP0 ^ed svStk  drop                    \ save return stack
  107. ;
  108.  
  109.  
  110. \ .ERR displays the error info saved by SAVE_ERR.  The value .stkLimit
  111. \  gives a maximum of stack cells dumped -- this can be used to keep
  112. \  info from scrolling off the screen.
  113.  
  114. big#    value    .stk_limit
  115. false    value    dumping?
  116.  
  117. : .ERR  { \ addr len ^obj \ ^ed -- }
  118.     dumping?  IF cr  EXIT  THEN
  119.  
  120.     ^errDump -> ^ed
  121.     ^ed @  -> len        1cell ++> ^ed
  122.     ^ed @  -> addr        1cell ++> ^ed
  123.  
  124.     setFwind    \ Redirected to abort word in installed applicns, so
  125.                 \  we don't try to type to the Mops window, which may
  126.                 \  well not exist.
  127.     true -> dumping?
  128.     5 beep  cr
  129.     len 0>
  130.     IF    addr len type  space    \ there's an error string
  131.     ELSE
  132.         len 0<
  133.         IF                        \ no error string - "addr" is
  134.                                 \  really an err number
  135.             addr 10 u>            \ err# 1-10 don't have messages - we
  136.                                 \  can use them for special things
  137.             IF  addr typeErrNum  THEN
  138.         THEN
  139.     THEN
  140.  
  141.     cr  src-start src-len type  cr    \ type error line
  142.     >in @ 1- spaces  & ^ emit  cr    \ and error position marker
  143.  
  144.     ^ed @   1cell ++> ^ed
  145.     -> ^obj
  146.     ^obj -1 <>
  147.     IF    ." Current object:  "
  148.         ^obj .objOrRA  cr
  149.     THEN
  150.  
  151.     ^ed @  cells -> len   1cell ++> ^ed
  152. \    .stk_limit 2dup > if nip else drop then  cells  -> len    
  153.     ." Stack:"
  154.     ^ed len over + false  (.stk)    len   ++> ^ed
  155.     ^ed @  cells -> len   1cell ++> ^ed
  156. \    .stk_limit min  cells  -> len    
  157.     ." Return stack:"
  158.     ^ed len over + true  (.stk)
  159.     big# -> .stk_limit
  160.     false -> dumping?
  161. ;
  162.  
  163. forward setup_cg
  164.  
  165. : dflt_abort
  166.     setup_cg            \ a bit drastic, but if the error is an index
  167.                         \  out of range on one of our register arrays,
  168.                         \  we'll just keep hitting the error!
  169.     origCDP IF  origCDP -> CDP  THEN
  170.     abortVec
  171.     SP0 4+ SP!  RP0 RP!  FSP0 16 +  FSP!
  172.     decimal
  173.     0  #TIB !  set_source  +curs
  174.     0 -> cstate
  175.     false -> local?
  176.     0 -> mod_seg#
  177.     QUIT
  178. ;
  179.  
  180. : dflt_abq
  181.     err_info_valid?
  182.     IF        3 -> .stk_limit  .err
  183.     ELSE    typeErrNum
  184.     THEN
  185.     dflt_abort
  186. ;
  187.  
  188.  
  189. forward        DFLT_DIE
  190.  
  191. : (ddie)
  192.     setFwind
  193.     0 -> (err#)            \ Clear error indicator from AppleEvents
  194.     dflt_abq  ;            \ Display error info and abort
  195.  
  196. :f dflt_die        (ddie)  ;f
  197.  
  198.  
  199. (*    CATCH  ( xt -- n )  EXECUTEs the xt.  If the executed word does a THROW,
  200.     n is the error code passed to THROW.  If it doesn't  do a THROW, n is
  201.     zero.  If it does a THROW, control doesn't return to CATCH, but to
  202.     whoever called CATCH.  See the Standard for a full description.
  203.     
  204.     We have to use assembly for setting this up, since we're manipulating
  205.     registers.
  206. *)
  207.  
  208. 0    value    THROW_HANDLER        \ holds the addr of the current throw handler
  209.                                 \  frame, or zero if none.
  210.  
  211. : frameErr
  212.     ." Return stack clobbered!"
  213.     dflt_abort
  214. ;
  215.  
  216.  
  217. : no_throw_handler ( n -- )        \ branched to from (THROW) if there's no
  218.                                 \  handler.  Takes the default action.
  219.  
  220.     errorVec                    \ set to error word in installed apps, so
  221.                                 \  we can bail out without Mops development
  222.                                 \  environment error handling
  223.  
  224.     dup -1 = IF  dflt_abort    THEN    \ -1: do default ABORT
  225.     dup -2 = IF  dflt_abq    THEN    \ -2: do default ABORT"
  226.     dflt_die
  227. ;
  228.  
  229.  
  230. :ppc_code  CATCH
  231.  
  232.     r0                    mflr,
  233.     r0        -4    rRP        stw,    \ save lr - our return addr
  234.     
  235.     r3        -16    rRP        stwu,    \ now save 1 cached stack cell (r3).  r4 is
  236.                                 \  xt for EXECUTE so we don't need to save it.
  237.                                 \ Note rRP must stay 8-byte aligned
  238.  
  239.     ' saves 2+            bl,
  240.     rRP        -48            addi,    \ now all our GPR locals (& keep rRP aligned)
  241.     ' fsaves 2+            bl,
  242.     rRP        -88            addi,    \ and all our FPR locals
  243.  
  244.     r0        $ 789A        li,
  245.     r0        -16    rRP        stwu,    \ create frame header and store marker
  246.     rSP        4    rRP        stw,    \ save SP at offs 4
  247.     r0        ' throw_handler 2+ @abs6 dicaddr
  248.                         lwz,
  249.     r0        8    rRP        stw,    \ and previous handler addr at offs 8
  250.     rRP        ' throw_handler 2+ @abs6 dicaddr
  251.                         stw,    \ and store RP (frame ptr) as new handler addr
  252.  
  253. ' execute 2+            bl,        \ execute the passed-in xt.  Note
  254.                                 \  this call only returns if THROW
  255.                                 \  isn't done.
  256.  
  257.     r0        0    rRP        lwz,    \ check our special marker is still
  258.     r0        $ 789A        cmpli,    \  on top of rtn stk
  259.  eq if,                            \ yep, all OK
  260.      r0        8    rRP        lwz,    \ get prev throw_handler from offs 8
  261.      r0    ' throw_handler 2+ @abs6  dicaddr
  262.                          stw,    \ restore previous throw_handler
  263.     
  264.      rRP        rRP    168        addi,    \ delete rest of frame - all regs OK already
  265.      r0        -4    rRP        lwz,    \ restore lr
  266.      r0                    mtlr,
  267. \     r3        -4    rSP        stwu,    \ we have 2 cached cells - push one off
  268. \     r3        r4            mr,
  269.      r4        r0    0        addi,    \ and return zero on top (means no error)
  270.                          blr,
  271.  then,
  272.         ' frameErr 2+    b,        \ rtn stk marker not there - call frameErr
  273.  
  274. ;ppc_code
  275.  
  276.  
  277. (*    THROW has two variants.  ThrowWithInfo is used by our normal error
  278.     word DIE, and also by ABORT", which both save the error info (including
  279.     a message string) before doing a normal throw.  This variant signals
  280.     that the saved error info is valid.  Our default error handler DFLT_DIE,
  281.     which is called if no throw handler has been installed, tests this flag
  282.     to decide whether to call .ERR to display the info.
  283.  
  284.     If THROW is called directly from code, it flags the error info invalid,
  285.     which prevents DFLT_DIE from calling .ERR and displaying spurious info.
  286. *)
  287.  
  288. :ppc_code (THROW)
  289.     r4        0    cmpli,            \ is THROW code nonzero
  290.  
  291. ne if,                            \ yes - we do the throw:
  292.      rX    ' throw_handler 2+ @abs6  dicaddr
  293.                          lwz,    \ restore previous throw_handler
  294.     rX        0    cmpli,            \ is there a throw handler?
  295.  
  296.  ne if,
  297.     r0        0    rX        lwz,    \ check our special marker is still
  298.     r0        $ 789A        cmpli,    \  on top of rtn stk
  299.   eq if,                        \ yep, all OK
  300.       rRP        rX            mr,        \ set RP to point to handler frame
  301.                                   \ Now we restore everything from the frame:
  302.       rSP        4    rRP        lwz,    \ rSP from offs 4
  303.        r0        8    rRP        lwz,
  304.      r0    ' throw_handler 2+ @abs6  dicaddr
  305.                          stw,    \ and previous throw_handler from offs 8
  306.      rRP        104            addi,
  307.      ' frestores 2+        bl,        \ restore FPR locals
  308.      rRP        48            addi,
  309.      ' restores 2+        bl,        \ and GPR locals
  310.      rRP        16            addi,    \ delete rest of frame
  311.  
  312.      r0        -4    rRP        lwz,    \ restore lr
  313.      r0                    mtlr,
  314.      r3        -16 rRP        lwz,    \ and cached stack cell (r3)
  315.                          blr,    \ and return to CATCH caller
  316.  
  317.   then,
  318.         ' frameErr 2+    b,        \ rtn stk marker not there - call frameErr
  319.  then,
  320.          ' no_throw_handler 2+    b,        \ no throw handler: take default action
  321. then,
  322.  
  323.     r4        r3            mr,        \ throw code zero - no error - just drop
  324.     r3        0    rSP        lwz,    \  the zero and return.
  325.     rSP        rSP    4        addi,
  326.                         blr,
  327. ;ppc_code
  328.  
  329.  
  330. :f THROW
  331.     false -> err_info_valid?  (throw)
  332. ;f
  333.  
  334. : THROW_WITH_INFO
  335.     true -> err_info_valid?  (throw)
  336. ;
  337.  
  338.  
  339. : ABORT
  340.     0 0 save_err  -1 throw  ;
  341.  
  342.  
  343. (*    ABORT" is immediate, so we've already defined it before CROSS
  344.     in qCond.  It gets the string parameter, then EVALUATEs do_abq
  345.     which we define here.  What we end up doing is in effect this:
  346.  
  347.         : ABORT"
  348.             postpone "
  349.             rot NIF  2drop  EXIT  THEN
  350.             save_err  -2 throw_with_info  ;        immediate
  351. *)
  352.  
  353. : do_abq
  354.     rot NIF  2drop  EXIT  THEN
  355.     save_err -2 throw_with_info  ;
  356.  
  357. 0    value    svErrNum
  358.  
  359. :f DIE
  360.     dup -> svErrNum  -1 save_err    \ -1 indicates to save_err that
  361.                                     \  this is an err#
  362.     svErrNum  throw_with_info
  363. ;f
  364.  
  365.  
  366. (* ****
  367.  
  368. \ THROW test:
  369.  
  370. : could-fail  key dup  & A = if  $ 1234 throw  then  ;
  371.  
  372. : doit    could-fail  nip nip nip  ;
  373.  
  374. : throwtest
  375. dbgr
  376.     1 2 3 ['] doit catch
  377. \ if there's no throw, the 1 2 3 will be dropped, and we'll get
  378. \  the typed key.  If throw is executed, we should get the 1 2 3
  379. \  and the error number $ 1234 on the stack.
  380.  
  381. dbgr dup
  382.     IF        ." Error was thrown" cr .s
  383.     ELSE    drop  ." The char was " emit cr
  384.     THEN  ;
  385.  
  386. **** *)
  387.  
  388.  
  389. : ?COMP
  390.     state  ?EXIT
  391.     -14 die  ;
  392.  
  393.  
  394. : ?STACK
  395.     depth dup 0<
  396.     IF  -4 die  THEN                    \ "stack underflow"
  397.     stack_size >= IF  -5 die  THEN        \ "stack overflow"
  398.     fdepth dup 0<
  399.     IF  -45 die  THEN                    \ "floating-point stack underflow"
  400.     fstack_size >= IF  -44 die  THEN    \ "floating-point stack overflow"
  401. ;
  402.  
  403. : ?EXEC
  404.     state  0EXIT
  405.     77 die  ;        \ "Execution state only"
  406.  
  407. : ?PAIRS
  408.     = ?EXIT
  409.     -22 die  ;        \ "Control structure mismatch"
  410.  
  411.  
  412. : ?DEFN
  413.     = ?EXIT
  414.     78 die  ;        \ "Unbalanced definition"
  415.  
  416. (*
  417.     (excep) is branched to from our exception handler in zObjInit.
  418.     We don't really know which regs held the top stack cells when the
  419.     exception occurred, so we just take as stab that it was r3 and r4.
  420.     The exception handler leaves the excep code in r5.  So we set up
  421.     (excep) with 3 named parms, which will be r3, r4 and r5.
  422.     
  423.     Here's Apple's defn of the exception codes:
  424.  
  425.     kUnknownException                = 0
  426.     kIllegalInstructionException     = 1
  427.     kTrapException                    = 2
  428.     kAccessException                = 3
  429.     kUnmappedMemoryException        = 4
  430.     kExcludedMemoryException        = 5
  431.     kReadOnlyMemoryException        = 6
  432.     kUnresolvablePageFaultException = 7
  433.     kPrivilegeViolationException     = 8
  434.     kTraceException                    = 9
  435.     kInstructionBreakpointException = 10
  436.     kDataBreakpointException        = 11
  437.     kIntegerException                = 12
  438.     kFloatingPointException            = 13
  439.     kStackOverflowException            = 14
  440.     kTerminationException            = 15
  441. *)
  442.  
  443. : (excep)  { x y ex# --  }
  444.     x y
  445.     ex# 210 +  die        \ we just assign all the message numbers appropriately
  446.                         \  so we don't have to do any other testing on the
  447.                         \  number.
  448. ;
  449.  
  450.  
  451.  
  452. \    ====================  ADDRESSING  =====================
  453.  
  454.  
  455. \ 16bits? ( n signed? -- n b )
  456. \  returns true if n will fit in 16 bits (signed or unsigned as requested).
  457.  
  458. : 16BITS?    \ ( n signed? -- n b )
  459.     IF    -32768 32767  within?
  460.     ELSE
  461.         dup 16 >> 0=
  462.     THEN
  463. ;
  464.  
  465. \ seg#>gpr# finds if the passed-in seg# corresponds to a currently
  466. \  set up base register.  If so, it returns the reg#.  If not, it
  467. \  returns zero.
  468.  
  469. : seg#>gpr#        \ ( seg# -- gpr# )
  470.  
  471.     CASE[  8    ]=>        mainCode_reg  EXIT
  472.         [  9    ]=>        mainData_reg  EXIT
  473.     DEFAULT=>
  474.     ]CASE
  475.  
  476.   ( seg# )
  477.   \  here we don't use case[ since the test values aren't constant.
  478.  
  479. \ dup $ 11 = if dbgr then
  480.       dup  mod_seg#        = IF  drop  modCode_reg  EXIT  THEN
  481.       dup  mod_seg# 1+    = IF  drop  modData_reg  EXIT  THEN
  482.       dup  comp_seg#        = IF  drop    modCode_reg  EXIT  THEN
  483.            comp_seg# 1+    = IF        modData_reg  EXIT  THEN
  484.  
  485.       0            \ failed -  return zero
  486. ;
  487.  
  488.  
  489. \ B&D takes the passed-in address and converts it to gpr# and displacement.
  490. \ We also store the appropriate segment # in seg#_to_use, in case we're
  491. \  generating a relocatable addr.
  492.  
  493. 0    value    seg#_to_use
  494.  
  495.  
  496. : s&d>b&d  { seg# displ \ displ' gpr# -- gpr# displ' }
  497.  
  498.     0 -> seg#_to_use
  499.     seg# seg#>gpr#  -> gpr#            \ will be zero if we didn't get a reg
  500.  
  501.     gpr# mainCode_reg =
  502.     IF
  503.         displ code_start + nuc_code_start -  half_displ_range -  -> displ'
  504.     
  505.         displ' true 16bits? nip
  506.         NIF                \ displ' doesn't fit in 16 bits, but we might have
  507.                         \  a const data pointer which we can use...
  508.             CD_gpr#
  509.             IF            \ if we've set it, we use it, since this will
  510.                         \  just about always give us a displ which fits
  511.                         \  in 16 bits
  512.                 CD_gpr# -> gpr#
  513.                 displ code_start + CD_gpr_loc -  -> displ'
  514.             THEN
  515.         THEN
  516.  
  517.         gpr# displ'  EXIT
  518.     THEN
  519.  
  520.  
  521.     gpr# mainData_reg =
  522.     IF                \ If the address is down in the code generator
  523.                     \  area and out of range from mainData_reg, we
  524.                     \  might be able to use RTOC instead, which of
  525.                     \  course points to the start of the data area.
  526.         mainData_reg
  527.         displ  data_start +  nuc_data_start -  half_displ_range -
  528. \        true 16bits?  ?EXIT
  529. \        
  530. \        displ true 16bits? nip
  531. \        IF    2drop  RTOC_reg  displ  THEN
  532.         EXIT
  533.     THEN
  534.  
  535.     gpr#
  536.     IF    seg# -> seg#_to_use
  537.         gpr#
  538.         displ half_displ_range -
  539.     ELSE            \ theAddr wasn't in range of any reg - return two zeros
  540.         0  0
  541.     THEN
  542. ;
  543.  
  544.  
  545.  
  546. : (B&D)  ( addr -- gpr# displ )
  547.     addr>S&D  s&d>b&d
  548. ;
  549.  
  550.  
  551. : B&D  { theAddr -- reg# displ }
  552.     theAddr (b&d) over
  553.     NIF     cr  theAddr .h ."   is an out-of-range addr!" 1 die  THEN
  554. ;
  555.  
  556.  
  557. \ @B&D fetches a relocatable addr and returns the "real" base
  558. \ gpr# and displacement.  This is used for going from the code
  559. \  area to the data area, for values etc.
  560.  
  561. : @B&D { addr \ relocAddr seg# displ gpr# -- gpr# displ' }
  562.     addr @  -> relocAddr
  563.     relocAddr  $ ffffff and  -> displ
  564.     relocAddr  24 >>  -> seg#
  565.     seg# displ  s&d>b&d
  566.     over NIF  70 die  THEN        \ seg# didn't refer to a loaded reg, or was just
  567.                                 \ garbage - "not a reloc addr"
  568. (*
  569.     seg# seg#>gpr#  -> gpr#
  570.  
  571.     gpr# mainCode_reg =
  572.     IF    mainCode_reg
  573.         displ code_start + nuc_code_start -  half_displ_range -
  574.         EXIT
  575.     THEN
  576.     
  577.     gpr# mainData_reg =
  578.     IF    mainData_reg
  579.         displ  data_start +  nuc_data_start -  half_displ_range -
  580.         EXIT
  581.     THEN
  582.  
  583.     gpr#
  584.     IF    gpr#  displ half_displ_range -
  585.                     \ machine instrns use a signed displ, so we
  586.                     \  point base regs 32k above the seg start
  587.                                         
  588.     ELSE            \ seg# didn't refer to a loaded reg, or was just garbage
  589.         70 die        \ " not a reloc addr"
  590.     THEN
  591. *)
  592. ;
  593.  
  594.  
  595. : RELOC!  { theAddr dest -- }
  596. \ theAddr $ 1000 u< if dbgr then
  597.     theAddr addr>S&D
  598.     $ ffffff and  swap  24 <<  or
  599.     dest !
  600. ;
  601.  
  602.  
  603.  
  604. \                ================================
  605. \                CONVERSION BETWEEN RELATIVE AND
  606. \                     ABSOLUTE ADDRESSES
  607. \                ================================
  608.  
  609. \ Note: @abs is already defined in Setup, since we needed it earlier.
  610.  
  611.  
  612. : DISPLACE   ( addr -- addr' )  inline{ dup @ dup if + else nip then}  ;
  613. : WDISPLACE  ( addr -- addr' )  inline{ dup w@x dup if + else nip then}  ;
  614.  
  615. : DISPL!  { src dst -- }
  616. \ Stores the source address as a relative address at the destination.
  617.     src dst -  dst !  ;
  618.  
  619. : WDISPL!  { src dst -- }
  620. \ Stores the source address as a short relative address at the destination
  621. \ (it is relative to the destination).
  622.     src dst -  dst w!  ;
  623.  
  624.  
  625. : reloc,        DP    reloc!  4 ++> DP   ;
  626. : relocCode,    CDP reloc!  4 ++> CDP  ;
  627. : displCode,    CDP displ!    4 ++> CDP  ;
  628.  
  629.  
  630.  
  631. \            =====================================
  632. \                    DICTIONARY OPERATIONS
  633. \            =====================================
  634.  
  635. forward defined?        \ needed by FORGET.  Defined in pnuc4.
  636.  
  637.  
  638. (*
  639. Patches_done is called on the 68k after any new instructions have been
  640. stored, or patches have been done, and before the instructions are
  641. executed.  It flushes the instruction cache if necessary.
  642.  
  643. On some PPC models there's also a separate icache and dcache, so we have
  644. to do the same sort of thing.  The appropriate sequence of ops must
  645. be executed with interrupts off, so Apple helpfully provides a call
  646. to do it -- MakeDataExecutable.
  647. *)
  648.  
  649. :f FIX_CACHES  { addr len -- }
  650.     len 0EXIT
  651.     addr len  %_MakeDataExecutable
  652. ;f
  653.  
  654.  
  655. \ : ALLOT        ( n -- )    ++> DP  ;
  656. : RESERVE    ( n -- )    DP over 0 fill  ++> DP  ;
  657.  
  658. : ,  ( n -- )    DP !    4 ++> DP  ;
  659. : W, ( n -- )    DP w!    2 ++> DP  ;
  660. : C, ( n -- )    DP c!    1 ++> DP  ;
  661.  
  662. : N, ( addr len -- )    >r  DP r@ cmove  r> allot  ;
  663.  
  664. : DISPL,  ( src -- )
  665.     DP -  ,  ;
  666.  
  667.  
  668. : code,        CDP !    4 ++> CDP  ;
  669. : codeW,    CDP w!    2 ++> CDP  ;
  670. : codeC,    CDP c!    1 ++> CDP  ;
  671.  
  672. : codeN,  ( addr len -- )
  673.     tuck
  674.     CDP swap cmove
  675.     ++> CDP
  676. ;
  677.  
  678. : ALIGN4
  679.     DP
  680.     4 reserve            \ just to ensure pad bytes are zero
  681.     3 +  $ fffffffc and  -> DP
  682. ;
  683.  
  684. : ALIGN8
  685.     DP
  686.     8 reserve
  687.     7 +  $ fffffff8 and  -> DP
  688. ;
  689.  
  690. : ALIGN        align4  ;
  691. : ALIGN-DP    align4  ;
  692.  
  693. : #ALIGN    inline{ 3+ -4 and}  ;        \ a synonym for #align4 (in pnuc1)
  694.                                         \  - on the PPC our default alignment is
  695.                                         \  4 byte
  696. : ALIGNED    inline{ 3+ -4 and}  ;        \ ANSI - same as #align4 on PPC
  697. : #ALIGN2    inline{ 1+ -2 and}  ;
  698.  
  699. \ #align4 is in pnuc1, since we need it early
  700.  
  701. : #ALIGN8    inline{ 7 +  $ fffffff8 and}  ;
  702. : #ALIGN16    inline{ 15 +  $ fffffff0 and}  ;
  703.  
  704. : #align_2**n    ( value n -- value' )
  705.     1 swap << 1- dup not down + and  ;
  706.             
  707.  
  708. : #OFF-ALIGN    \ ( n -- n' )  Aligns to the 2-byte boundary between
  709.                 \  adjacent 4-byte boundaries.
  710.     5 + $ fffffffc and 2-  ;
  711.  
  712.  
  713.  
  714. : code_allot    ++> CDP  ;
  715. : code_reserve    CDP over erase  ++> CDP  ;
  716. : code_align    CDP 4 erase  CDP #align4  -> CDP  ;
  717.  
  718.  
  719.  
  720. \ FORGET isn't really adequate on the PPC, since it can't handle the
  721. \  data area or syscall_chain etc.  But I'll keep it for backward
  722. \  compatibility, and it can be called by MARKER anyway to do the
  723. \  part of the job that it can.
  724.  
  725.  
  726. \ Trim  ( lfa -- new_latest )  is called by (forget).
  727.  
  728. : trim  { lfa \ cxt nxt link new_lfa -- new_latest }
  729.  
  730.     0 -> new_lfa
  731.     #threads FOR
  732.         context  i  2 <<  +  dup -> cxt        \ addr of this context entry
  733.         displace
  734.         BEGIN    dup lfa u>=
  735.         WHILE    displace
  736.         REPEAT
  737.     \ new context value for this thread
  738.         dup new_lfa umax -> new_lfa
  739.         cxt displ!
  740.     NEXT
  741.     new_lfa l>name        \ new link field -> new name field, which
  742.                         \  will become the new LATEST
  743. ;
  744.  
  745.  
  746. : (FORGET)  { lfa -- }
  747.     lfa fence u< IF  -15 die  THEN        \ "invalid FORGET"
  748.     lfa trim  -> latest
  749.  
  750. \ now we reset CDP to lfa.  First we call fix_caches on the range
  751. \  we're wiping out, since it doesn't exist any more, and we're
  752. \  a bit paranoid.
  753.  
  754.     lfa                    \ where we're wiping out from
  755.     CDP lfa -            \ # bytes we're wiping out
  756.     fix_caches
  757.     lfa -> CDP            \ reset CDP to new spot
  758. ;
  759.  
  760.  
  761. : FORGET
  762.     defined? ?notfound        \ i.e. tick - but we can't define that yet since
  763.                             \  we still need the 68k tick.  It's in qpCond.
  764.     >link (forget)  ;
  765.  
  766.  
  767.  
  768. \        =============  Module-related words  ===================
  769.  
  770. (*    There are a few module-related words which we use in the class
  771.     code.  Holdmod is forward defined, and resolved in zModules.  Of
  772.     course it should never need to be executed before zModules is loaded!
  773.     
  774.     unholdMod and ?unholdMod don't release the module as they do on
  775.     the 68k - once a module is loaded it stays put.  So all these words
  776.     have to do here is clear heldMod.
  777. *)
  778.  
  779. forward  holdMod
  780.  
  781. : unholdMod        0 -> heldMod  ;
  782. : ?unholdMod    0 -> heldMod  ;
  783.  
  784.  
  785. : ?>classInMod  ( ^class -- ^class' )
  786. \    0 -> seg#_accessed    \ leave zero if we don't go into a module
  787.     dup 2- w@            \ class handler code
  788.     $ BC2D =
  789.     IF    holdMod            \ if class_in_mod_h, replaces ^class with the
  790.                         \  xt of the class in the mod, and holds it.
  791.     THEN
  792. ;
  793.  
  794.  
  795. endload
  796.